package com.springx.examples.showcase.service;

import com.github.orderbyhelper.OrderByHelper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort.Order;
import org.springframework.transaction.annotation.Transactional;
import com.springx.modules.persistence.SearchFilter;
import com.springx.starter.utils.GenericsUtils;
import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.entity.Example;

import java.util.List;
import java.util.Map;

/**
 * Created by test on 2015/7/10.
 */
public abstract class BaseService<T> {

    protected Logger logger = LoggerFactory.getLogger(this.getClass());

    protected Class<T> entityClass = GenericsUtils.getSuperClassGenricType(this.getClass());

    @Autowired
    protected Mapper<T> mapper;

    public int insert(T entity) {
        return mapper.insertSelective(entity);
    }

    public int deleteByPrimaryKey(Long id) {
        return mapper.deleteByPrimaryKey(id);
    }

    public int deleteByExample(T entity) {
        return mapper.deleteByExample(entity);
    }

    public void delete(Long[] ids) {
         if(ArrayUtils.isNotEmpty(ids)){
            for(Long id:ids){
                mapper.deleteByPrimaryKey(id);
            }
         }
    }

    public int updateByPrimaryKeySelective(T entity) {
        return mapper.updateByPrimaryKeySelective(entity);
    }

    public int updateByExample(T entity, Example example) {
        return mapper.updateByExample(entity, example);
    }

    public int updateByExampleSelective(T entity, Example example) {
        return mapper.updateByExampleSelective(entity, example);
    }

    @Transactional(readOnly = true)
    public T select(Long id) {
        return mapper.selectByPrimaryKey(id);
    }

    @Transactional(readOnly = true)
    public T selectOne(T entity) {
        return mapper.selectOne(entity);
    }

    @Transactional(readOnly = true)
    public List<T> selectAll() {
        return mapper.select(null);
    }

    /**
     * 根据条件查询列表
     *
     * @param orders
     * @return
     */
    @Transactional(readOnly = true)
    public List<T> selectList(Map<String, Object> searchParams, List<Order> orders) {
        Example example = new Example(entityClass);
        buildEaxmple(searchParams, example.createCriteria());
        if (CollectionUtils.isNotEmpty(orders)) {
            StringBuffer bf = new StringBuffer();
            for (Order order : orders) {
                bf.append(order.getProperty()).append(" ").append(order.getDirection()).append(",");
            }
            OrderByHelper.orderBy(bf.toString());
        }
        List<T> tList = mapper.selectByExample(example);
        return tList;
    }


    private void buildEaxmple(Map<String, Object> searchParams, Example.Criteria criteria) {

        Map<String, SearchFilter> filters = SearchFilter.parse(searchParams);
        //<editor-fold desc="build search conditon">
        for (SearchFilter filter : filters.values()) {
            if (SearchFilter.Operator.EQ.compareTo(filter.operator) == 0) {
                criteria.andEqualTo(filter.fieldName, filter.value);
            } else if (SearchFilter.Operator.GT.compareTo(filter.operator) == 0) {
                criteria.andGreaterThan(filter.fieldName, filter.value);
            } else if (SearchFilter.Operator.GTE.compareTo(filter.operator) == 0) {
                criteria.andGreaterThanOrEqualTo(filter.fieldName, filter.value);
            } else if (SearchFilter.Operator.LT.compareTo(filter.operator) == 0) {
                criteria.andLessThan(filter.fieldName, filter.value);
            } else if (SearchFilter.Operator.LTE.compareTo(filter.operator) == 0) {
                criteria.andLessThanOrEqualTo(filter.fieldName, filter.value);
            } else if (SearchFilter.Operator.IN.compareTo(filter.operator) == 0) {
                criteria.andIn(filter.fieldName, (List) filter.value);
            } else if (SearchFilter.Operator.LIKE.compareTo(filter.operator) == 0) {
                criteria.andLike(filter.fieldName, "%"+ConvertUtils.convert(filter.value)+"%");
            } else if (SearchFilter.Operator.NULL.compareTo(filter.operator) == 0) {
                criteria.andIsNull(filter.fieldName);
            } else if (SearchFilter.Operator.NOTNULL.compareTo(filter.operator) == 0) {
                criteria.andIsNotNull(filter.fieldName);
            }

        }
        //</editor-fold>
    }

    @Transactional(readOnly = true)
    public long count() {
        return mapper.selectCount(null);
    }

    @Transactional(readOnly = true)
    public long count(T entity) {
        return mapper.selectCount(entity);
    }

    @Transactional(readOnly = true)
    public long count(Map<String, Object> searchParams) {
        Example example = new Example(entityClass);
        buildEaxmple(searchParams, example.createCriteria());
        return mapper.selectCountByExample(example);
    }

    @Transactional(readOnly = true)
    public boolean exists(T entity) {
        return mapper.selectCount(entity) > 0 ? true : false;
    }

    @Transactional(readOnly = true)
    public boolean exists(Map<String, Object> searchParams) {
        return count(searchParams) > 0 ? true : false;
    }

    @Transactional(readOnly = true)
    public Page<T> selectPage(Map<String, Object> searchParams, List<Order> orders, Pageable pageable) {
        Example example = new Example(entityClass);
        buildEaxmple(searchParams, example.createCriteria());
        if (CollectionUtils.isNotEmpty(orders)) {
            StringBuffer bf = new StringBuffer();
            for (Order order : orders) {
                bf.append(order.getProperty()).append(" ").append(order.getDirection()).append(",");
            }
            PageHelper.orderBy(bf.toString());
        }
        PageHelper.startPage(pageable.getPageNumber()+1, pageable.getPageSize());
        List<T> tList = mapper.selectByExample(example);
        PageInfo<T> pageInfo = new PageInfo<T>(tList);
        Page<T> page = new PageImpl<T>(pageInfo.getList(),pageable, pageInfo.getTotal());
        return page;
    }
}


